#include "ET++.ph"
#ifdef __GNUG__
#pragma implementation
#endif

#include "Class.h"
#include "ClassManager.h"
#include "VObject.h"
#include "Alert_e.h"
#include "Filler.h"
#include "Picture.h"
#include "PictureItem.h"
#include "ImageItem.h"
#include "FileData.h"
#include "System.h"
#include "PathLookup.h"
#include "FileDialog.h"
#include "Window.h"
#include "String.h"
#include "Env.h"
#include "OrdColl.h"

#include "TextMarks.h"

static PathLookup *pictPath;
static FileDialog *fileDialog;

ONEXIT(TextMarks)
{
	SafeDelete(pictPath);
	SafeDelete(fileDialog);
}

//---- VisualMark --------------------------------------------------------------

NewMetaImpl(VisualMark,Mark, (TP(tag)));

VisualMark::VisualMark() : Mark(0, 0, eStateNone, eMarkFixedSize)
{
	tag= 0;
}

VisualMark::VisualMark(const char *t) : Mark(0, 0, eStateNone, eMarkFixedSize)
{
	tag= strsave(t);
}

VisualMark::~VisualMark()
{
	SafeDelete(tag);
}

void VisualMark::CalcExtent()
{
}

int VisualMark::Base()
{
	return GetExtent().y;
}

Point VisualMark::GetExtent()
{
	return gPoint0;
}

void VisualMark::Draw(const Point&, const Rectangle&, const Rectangle&, bool)
{
}

void VisualMark::SendDown(int, int, void*)
{
}

void VisualMark::SetContainer(VObject*)
{
}

bool VisualMark::WantsInput(Point)
{
	return FALSE;
}

Command *VisualMark::Input(Point, Token&, Clipper*)
{
	return 0;
}

VObject *VisualMark::GetVObject()
{
	return 0;
}

void VisualMark::SetTag(const char *t)
{
	strreplace(&tag, t);
}

//---- VObjectMark -------------------------------------------------------------

NewMetaImpl(VObjectMark,VisualMark, (TP(vop), T(sizeHint)));

VObjectMark::VObjectMark(VObject *v, const Point &sh) : vop(v), sizeHint(sh)
{
}

VObjectMark::VObjectMark(VObject *v, const char *t, const Point &sh)
					: vop(v), sizeHint(sh), VisualMark(t)
{
}

VObjectMark::VObjectMark(const char *t, const Point &sh)
					: vop(0), sizeHint(sh), VisualMark(t)
{
}

VObjectMark::~VObjectMark()
{
	SafeDelete(vop);
}

void VObjectMark::InitNew()
{
	sizeHint= gPoint_1;
}

VObject *VObjectMark::GetVObject()
{
	if (vop == 0)
		vop= new Filler(sizeHint, ePatGrey50);
	return vop;
}

void VObjectMark::CalcExtent()
{
	if (vop)
		vop->CalcExtent();
}

Point VObjectMark::GetExtent()
{
	if (sizeHint != gPoint_1)
		return sizeHint;
	return GetVObject()->GetExtent();
}

int VObjectMark::Base()
{
	if (sizeHint != gPoint_1)
		return sizeHint.y;
	return GetVObject()->Base();
}

void VObjectMark::SetContainer(VObject *cont)
{
	GetVObject()->SetContainer(cont);
	if (cont->IsOpen())
		vop->Open();
}

void VObjectMark::Draw(const Point &at, const Rectangle &clip,
						const Rectangle&, bool border)
{
	GetVObject()->SetOrigin(at);
	vop->DrawAll(clip, FALSE);
	if (border) {
		GrSetPenInk(ePatGrey50);
		GrStrokeRect(vop->ContentRect());
	}
}

void VObjectMark::SendDown(int what, int p, void *arg)
{
	GetVObject()->SendDown(what, p, arg);
}

bool VObjectMark::WantsInput(Point lp)
{
	return GetVObject()->ContainsPoint(lp);
}

Command *VObjectMark::Input(Point lp, Token &t, Clipper *cl)
{
	return GetVObject()->Input(lp, t, cl);
}

void VObjectMark::FreeAll()
{
	if (vop) {
		vop->FreeAll();
		SafeDelete(vop);
	}
}

OStream &VObjectMark::PrintOn(OStream &s)
{
	VisualMark::PrintOn(s);
	GetVObject();
	return s << vop->ClassName() SP << vop->GetExtent() SP << vop SP << '\007';
}

IStream &VObjectMark::ReadFrom(IStream &s)
{
	VisualMark::ReadFrom(s);

	if (IsA()->LoadVersion() < 3.1) {
		s >> vop;
	} else {
		char c, className[100];
		Point extent;
		
		s >> className >> extent;
		
		if (gClassManager->Find(className)) {
			s >> vop;
			vop->SetExtent(extent);
		} else
			vop= new Filler(extent, ePatGrey50);

		while (s.get(c))
			if (c == '\007')
				break;
	}
	return s;
}

void VObjectMark::CollectParts(Collection *col)
{
	VisualMark::CollectParts(col);
	if (vop)
		col->Add(vop);
}

//---- ReferenceMark -----------------------------------------------------------

NewMetaImpl(ReferenceMark,VObjectMark, (TP(data), TP(tag)));

ReferenceMark::ReferenceMark(const char *filename, const Point &sh)
						: VObjectMark((VObject*)0, sh)
{
	data= new FileData(filename);
	if (data)
		data->Ref();
	VerifyData();
}

ReferenceMark::ReferenceMark(const char *filename, const char *t) : VObjectMark(t)
{
	data= new FileData(filename);
	if (data)
		data->Ref();
	VerifyData();
}

ReferenceMark::ReferenceMark(Data *d, const Point &sh)
						: VObjectMark((VObject*)0, sh)
{
	data= d;
	if (data)
		data->Ref();
	VerifyData();
}

ReferenceMark::~ReferenceMark()
{
	SafeUnref(data);
}

void ReferenceMark::SetContainer(VObject *v)
{
	container= v;
}

OStream &ReferenceMark::PrintOn(OStream &s)
{
	VisualMark::PrintOn(s);
	s << sizeHint SP;
	return s.PrintString(data->FullName());
}

IStream &ReferenceMark::ReadFrom(IStream &s)
{
	char *fn= 0;
	VisualMark::ReadFrom(s);
	vop= 0;
	s >> sizeHint;
	s.ReadString(&fn);
	SafeUnref(data);
	data= new FileData(fn);
	SafeDelete(fn);
	VerifyData();
	return s;
}

const char *ReferenceMark::FileName()
{
	return data->FullName();
}

VObject *ReferenceMark::GetVObject()
{
	if (vop)
		return vop;

	Object *op;

	if (vop == 0 && (op= data->AsObject(Meta(Picture))))
		vop= new PictureItem((Picture*)op);

	if (vop == 0 && (op= data->AsObject(Meta(Bitmap))))
		vop= new ImageItem((Bitmap*)op);

	if (vop == 0 && (op= data->AsObject(Meta(VObject))))
		vop= (VObject*)op;

	if (vop == 0) {
		ShowAlert(eAlertNote, "Cannot Convert @B%s @P (%s)\n",
					data->Name(), data->Type().AsString());
		vop= new Filler(Point(100), ePatGrey25);
	}

	vop->SetContainer(container);
	if (container && container->IsOpen())
		vop->Open();
	vop->CalcExtent();
	if (sizeHint != gPoint_1)
		vop->SetExtent(sizeHint);

	return vop;
}

void ReferenceMark::VerifyData()
{
	/*
	if (!data->IsValid()) {
		ShowAlert(eAlertNote, "Not readable: @B%s @P (%s)\n",
						data->Name(), data->Type().AsString());
		vop= new Filler(Point(100), ePatGrey25);
		return;
	}
	*/
	
	if (data->IsKindOf(FileData)) {
		FileData *fd= (FileData*) data;
		char docPathName[1024];
		
		if (pictPath == 0)
			pictPath= new PathLookup(Symbol("CodeText.PicturePath"));

		if (!pictPath->Lookup(fd->FullName(), docPathName)) {              
			if (!pictPath->Lookup(fd->GetBaseName(), docPathName)) {
				if (fileDialog == 0)
					fileDialog= new FileDialog;
				char *title= form("Show the Location of %s", fd->GetBaseName());
				if (fileDialog->ShowInWindow(eFDRead, gWindow, 0, title) == cIdOk) {
					gSystem->ChangeDirectory(fileDialog->GetInitDir());
					fd->SetName(fileDialog->FileName());
					pictPath->Add(fd->GetLoadDir());
				} else
					vop= new Filler(Point(100), ePatGrey25);
				return;
			}
		}
		fd->SetName(docPathName);
	}
}

